﻿
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using fc2editor.DataModel;
using fc2editor.DataModel.Descriptors;
using fc2editor.Services;
using fc2editor.Utils;
namespace fc2editor.Lua
{
    public class AircraftParser
    {
        //^return \w+\("{(.*)}"\s*,\s*"(.*)"\s*,.*
        private static readonly Regex PlaneHeaderRegex = new Regex("^return \\w+\\(\"{(.*)}\"\\s*,\\s*\"(.*)\"\\s*,.*");

        //^pylon\((\d+),(.*),\s*(.*),\s*(.*),\s*(.*),$
        private static readonly Regex PylonRegex = new Regex("^pylon\\((\\d+),(.*),\\s*(.*),\\s*(.*),\\s*(.*),$");

        //^{\s*CLSID\s*=\s*"{(.*)}"\s*},$
        private static readonly Regex PylonWeaponRegex = new Regex("^{\\s*CLSID\\s*=\\s*\"{(.*)}\"\\s*},$");

        //^(\w+) = "(.+)",
        private static readonly Regex AircraftPropertyRegex = new Regex("^(\\w+) = \"(.+)\",");

        //^FiZ\s*=(.*),$
        private static readonly Regex FizRegex = new Regex("^FiZ\\s*=(.*),$");

        //^absent\s*=\s*(\d+),$
        private static readonly Regex AbsentRegex = new Regex("^absent\\s*=\\s*(\\d+),$");

        //aircraft_task\((.*)\),
        private static readonly Regex TaskRegex = new Regex("^aircraft_task\\((.*)\\),");

        //aircraft_task\((.*)\)
        private static readonly Regex DefaultTaskRegex = new Regex("^aircraft_task\\((.*)\\)");


        public AircraftParser(IWeaponService weaponService)
        {
            this.weaponService = weaponService;
        }

        public Aircraft Parse(string fileName, AircraftType aType)
        {
            AircraftDescriptor descriptor = new AircraftDescriptor();

            using (var fs = File.OpenRead(fileName))
            {
                using (var reader = new StreamReader(fs))
                {
                    if (!reader.EndOfStream)
                    {
                        var line = reader.ReadLine().Trim();
                        var m = PlaneHeaderRegex.Match(line);
                        if (m.Success)
                        {
                            descriptor.ID = Guid.Parse(m.Groups[1].Value);
                            descriptor.Name = m.Groups[2].Value;
                            descriptor.FileName = fileName;
                            descriptor.Type = aType;
                        }
                        else
                            return null;
                    }
                    else
                        return null;

                    while (!reader.EndOfStream)
                    {
                        var line = reader.ReadLine().Trim();



                        if (!line.StartsWith("pylon") && !parsingPylons)
                        {
                            if (line.StartsWith("Picture"))
                            {
                                var m = AircraftPropertyRegex.Match(line);
                                if (m.Success)
                                {
                                    descriptor.Picture = m.Groups[2].Value;
                                }
                            }

                            if (line.StartsWith("aircraft_task"))
                            {
                                if (!parsingTasks)
                                {
                                    parsingTasks = true;
                                }

                                if (parsingTasks)
                                {
                                    do
                                    {
                                        var m = TaskRegex.Match(line);
                                        if (m.Success)
                                        {
                                            descriptor.Tasks.Add(m.Groups[1].Value);
                                        }
                                        line = reader.ReadLine().Trim();
                                    }
                                    while (line != "},");

                                    //default task
                                    line = reader.ReadLine().Trim();
                                    var m2 = DefaultTaskRegex.Match(line);
                                    if (m2.Success)
                                    {
                                        descriptor.DefaultTask = m2.Groups[1].Value;
                                    }
                                }
                            }
                            continue;
                        }
                        else
                        {
                            if (line.StartsWith("pylon"))
                            {
                                var m = PylonRegex.Match(line);
                                if (m.Success)
                                {
                                    parsingPylons = true;
                                    int pylonIndex = Convert.ToInt32(m.Groups[1].Value);
                                    var formatProvider = new LuaFloatFormatProvider();
                                    float[] coord = new float[4]
                                    {
                                        Convert.ToSingle( m.Groups[2].Value, formatProvider ),
                                        Convert.ToSingle( m.Groups[3].Value, formatProvider),
                                        Convert.ToSingle( m.Groups[4].Value, formatProvider),
                                        Convert.ToSingle( m.Groups[5].Value, formatProvider),
                                    };
                                    pylonDescriptor = new PylonDescriptor()
                                    {
                                        Index = pylonIndex,
                                        Coordinates = coord
                                    };
                                    //currentPylon = new Pylon(pylonIndex);
                                    //descriptor.Pylons.Add(currentPylon);
                                }
                            }
                            else if (parsingPylons)
                            {
                                do
                                {
                                    line = reader.ReadLine().Trim();
                                    var m = FizRegex.Match(line);
                                    if (m.Success)
                                    {
                                        pylonDescriptor.Fiz = Convert.ToSingle(m.Groups[1].Value, new LuaFloatFormatProvider());
                                    }

                                    m = AbsentRegex.Match(line);
                                    if (m.Success)
                                    {
                                        pylonDescriptor.Absent = true;
                                        pylonDescriptor.AbsentValue = Convert.ToInt32(m.Groups[1].Value);
                                    }
                                } while (line != "},");

                                do
                                {
                                    line = reader.ReadLine().Trim();
                                    var m = PylonWeaponRegex.Match(line);
                                    if (m.Success)
                                    {
                                        var weaponID = Guid.Parse(m.Groups[1].Value);
                                        var weapon = weaponService.GetWeaponByID(weaponID);
                                        if (weapon != null)
                                        {
                                            pylonDescriptor.Weapons.Add(weapon);
                                        }
                                        else
                                            throw new NullReferenceException("Illegal null-reference weapon for pylon");
                                    }
                                } while (line != "),");

                                var pylon = new Pylon(pylonDescriptor);
                                descriptor.Pylons.Add(pylon);

                                parsingPylons = false;
                            }
                        }
                    }
                    parsingPylons = false;
                }
            }

            //reverse pylons due-to image picture
            var reversedPylons = descriptor.Pylons.OrderByDescending(p => p.Index);
            descriptor.Pylons = reversedPylons.ToList();

            return new Aircraft(descriptor);
        }

        private IWeaponService weaponService;
        private bool parsingPylons;
        private bool parsingTasks;
        private PylonDescriptor pylonDescriptor;
    }
}
